#ifndef _COUNTER_H_
#define _COUNTER_H_

#include "util/common_macros.h"		// macros
#include "util/delegate.h"		// macros

namespace math
{
///////////////////////////////////////////////////////
///	\brief	Counter base class
///////////////////////////////////////////////////////
class Counter
{
public:
	Counter(float	CountLimit = 0.0f)
	{
		m_Limit = CountLimit;
		Reset();
	}
	virtual			~Counter()
	{

	}
	virtual void	Tick(float dt)
	{
		m_Counter -= dt;
	}
	virtual void	TickSafe(float dt)
	{
		Tick(dt);
		if(m_Counter <-0.00001f)
			m_Counter = -0.00001f;
	}
	void			Reset()	
	{
		m_Counter = m_Limit;
	}
	bool			IsReady() const
	{ 
		return m_Counter < 0; 
	};
	void			ForceReady()
	{
		m_Counter = -1;
	}
	void			SetLimit(float f) { m_Limit = f; Reset(); };
	float			GetLimit() const { return m_Limit; };
	float			GetCounter() const { return m_Counter; };
	float			GetInvCounter() const { return m_Limit - m_Counter; };
	void			SetCounter(float f) { m_Counter = f; };
	void			SetCounterSafe(float f) {m_Counter = f; if (m_Limit < m_Counter) m_Limit = m_Counter;};
	float			GetProgress() const { float f = 1.0f - (m_Counter/m_Limit); UTIL_CLAMP(f, 0, 1); return f; };

protected:
	float			m_Limit;
	float			m_Counter;
};

class	CallbackCounter : public Counter
{
public:
	typedef void (*CounterCB)(CallbackCounter* pCounter, void* pData);
		
	CallbackCounter(float CounterLimit = 0.0f, CounterCB pCB = 0, void* pData = 0) :
		Counter(CounterLimit)
	{
		m_pCB		= pCB;
		m_pData		= pData;
	}
	~CallbackCounter()
	{

	}
	virtual void	Tick(float dt)
	{
		bool	Ready = IsReady();
		m_Counter -= dt;
		if (Ready && !IsReady())
		{
			if (m_pCB)
			{
				m_pCB(this, m_pData);
			}
		}
	}
	void		SetCB(CounterCB		pCB)	{ m_pCB = pCB; };
	void		SetData(void*	pData)		{ m_pData = pData; };

private:
	CounterCB		m_pCB;
	void*			m_pData;
};

class	DelegateCounter : public Counter
{
public:
	typedef util::Delegate1<void*>	tdgCallback;

	DelegateCounter(float CounterLimit = 0.0f, tdgCallback pCB = 0, void* pData = 0) :
		Counter(CounterLimit)
	{
		m_Callback = pCB;
		m_pData		= pData;
	}
	~DelegateCounter()
	{

	}
	virtual void	Tick(float dt)
	{
		bool	Ready = IsReady();
		m_Counter -= dt;
		if (Ready && !IsReady())
		{
			if (m_Callback) {
				m_Callback(m_pData);
			}
		}
	}
	void		SetCB(tdgCallback		pCB)	{ m_Callback = pCB; };
	void		SetData(void*	pData)		{ m_pData = pData; };

private:
	tdgCallback		m_Callback;
	void*			m_pData;
};

class CounterNumber
{
public:
	CounterNumber() { m_Start = m_Target = m_Current = 0.0f; m_Speed = 1.0f; };
	~CounterNumber() {} ;

	void			Setup(float start, float end, float time) { SetStartValue(start); SetLimit(end); SetCountTime(time); };
	void			SetStartValue(float Start = 0.0f) { m_Start = m_Current = Start; };
	void			SetLimit(float	Target) { m_Target = Target; };
	void			SetSpeed(float CountSpeed) { m_Speed = CountSpeed; };
	void			SetCountTime(float Time) { m_Speed = (m_Target-m_Start)/Time; };
	
	void			Tick(float dt) { m_Current += m_Speed*dt; if (m_Current > m_Target) m_Current = m_Target; };
	float			GetCurrentNumber() const { return m_Current; };
	void			SetFinished() { m_Current = m_Target; };
	bool			IsFinished() const { return m_Current >= m_Target; };
private:
	float			m_Start, m_Target, m_Current;
	float			m_Speed;
};

} // namespace math

#endif // _COUNTER_H_